﻿using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System;
using System.Collections.Concurrent;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using SuperX.Common.MSG;
using System.Linq;

namespace SuperX.Common.Collection
{
    // 
    [Serializable]
    public class ObjectCollection<TC, T> : IList, ICollection, IEnumerable where TC : IObjCollection where T : class, IBasicObject
    {
        // 
        public ObjectCollection() : this(default(TC))
        {
        }

        // 
        public ObjectCollection(TC parent)
        {
            this._parent = parent;
            this._collectionList = new List<T>();
            this._collectionDictionary = new ConcurrentDictionary<string, T>();
        }

        // 
        public T this[string key]
        {
            get
            {
                T t;
                this._collectionDictionary.TryGetValue(key, out t);
                if (t != null && t.Name == null)
                {
                    return default(T);
                }
                return t;
            }
        }

        // 
        public void SetParent(TC parent)
        {
            if (parent == null)
            {
                return;
            }
            this._parent = parent;
            foreach (T t in this._collectionList)
            {
                t.Parent = this._parent;
            }
        }

        // 
        public IEnumerator<T> GetEnumerator()
        {
            return this._collectionList.GetEnumerator();
        }

        // 
        public bool Remove(T item)
        {
            if (item == null)
            {
                return false;
            }
            item.Renamed -= this.item_Renamed;
            this._collectionList.Remove(item);
            T t;
            this._collectionDictionary.TryRemove(item.Name,out t);
            TC tc = this._parent;
            if (tc != null)
            {
                tc.NotifyItemRemoved(item);
            }
            item.Parent = null;
            item.Dispose();
            return true;
        }

        // 
        public void CopyTo(Array array, int index)
        {
            this._collectionList.CopyTo((T[])array, index);
        }

        // 
        public int Count
        {
            get
            {
                return this._collectionList.Count;
            }
        }

        // 
        public object SyncRoot { get; private set; }

        // 
        public bool IsSynchronized { get; private set; }

        // 
        public int Add(object value)
        {
            return this.AddHelper(this.Cast(value));
        }

        // 
        public void Add(T value)
        {
            this.AddHelper(value);
        }

        // 
        public bool Contains(object value)
        {
            return this._collectionList.Contains(this.Cast(value));
        }

        // 
        public void Clear()
        {
            foreach (T t in this._collectionList)
            {
                t.Renamed -= this.item_Renamed;
                t.Parent = null;
            }
            this._collectionList.Clear();
            this._collectionDictionary.Clear();
            TC tc = this._parent;
            if (tc == null)
            {
                return;
            }
            tc.NotifyItemCleared();
        }

        // 
        public int IndexOf(object value)
        {
            return this._collectionList.IndexOf(this.Cast(value));
        }

        // 
        public void Insert(int index, object value)
        {
            if (value == null)
            {
                return;
            }
            T item = this.Cast(value);
            this.Insert(index, item);
        }

        // 
        public void Remove(object value)
        {
            this.Remove(this.Cast(value));
        }

        // 
        public void RemoveAt(int index)
        {
            if (index >= this._collectionList.Count)
            {
                return;
            }
            this.Remove(this._collectionList[index]);
        }

        // 
        object IList.this[int index]
        {
            get
            {
                return this._collectionList[index];
            }
            set
            {
                this._collectionList[index] = this.Cast(value);
            }
        }

        // 
        public bool IsReadOnly { get; private set; }

        // 
        public bool IsFixedSize { get; private set; }

        // 
        private int AddHelper(T item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }
            if (string.IsNullOrEmpty(item.Name) || this._collectionDictionary.ContainsKey(item.Name))
            {
                throw new Exception("name is null or name already exists");
            }
            item.Parent = this._parent;
            int count = this._collectionList.Count;
            this._collectionList.Add(item);
            this.AddItemToDictionary(item);
            return count;
        }

        // 
        public bool Contains(T item)
        {
            return this._collectionList.Contains(item);
        }

        // 
        public void CopyTo(T[] array, int arrayIndex)
        {
            this._collectionList.CopyTo(array, arrayIndex);
        }

        // 
        public int IndexOf(T item)
        {
            return this._collectionList.IndexOf(item);
        }

        // 
        public void Insert(int index, T item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }
            if (string.IsNullOrEmpty(item.Name) || this._collectionDictionary.ContainsKey(item.Name))
            {
                throw new Exception("name is null or name already exists");
            }
            item.Parent = this._parent;
            this._collectionList.Insert(index, item);
            this.AddItemToDictionary(item);
        }

        // 
        public T this[int index]
        {
            get
            {
                return this._collectionList[index];
            }
            set
            {
                this._collectionList[index] = value;
            }
        }

        // 
        protected virtual T Cast(object value)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }
            if (value is JContainer)
            {
                value = JsonConvert.DeserializeObject<T>(value.ToString());
            }
            T result;
            try
            {
                T t = (T)((object)value);
                if (t == null)
                {
                    throw new ArgumentException(typeof(T).FullName + "is error");
                }
                result = t;
            }
            catch (Exception)
            {
                throw new ArgumentException(typeof(T).FullName + "is error");
            }
            return result;
        }

        // 
        private void AddItemToDictionary(T item)
        {
            this._collectionDictionary.TryAdd(item.Name, item);
            item.Renamed += this.item_Renamed;
            TC tc = this._parent;
            if (tc == null)
            {
                return;
            }
            tc.NotifyItemAdded(item);
        }

        // 
        public void Sort(Comparison<T> comparison)
        {
            this._collectionList.Sort(comparison);
        }

        // 
        public T Find(Predicate<T> match)
        {
            return this._collectionList.Find(match);
        }

        //
        public void ForEach(Action<T> action)
        {
            this._collectionList.ForEach(action);
        }

        // 
        IEnumerator IEnumerable.GetEnumerator()
        {
            return this._collectionList.GetEnumerator();
        }

        // 
        private void item_Renamed(object sender, IotRenamedEventArgs e)
        {
            IBasicObject item = e.Item;
            T t;
            this._collectionDictionary.TryRemove(e.OldName, out t);
            this._collectionDictionary.TryAdd(item.Name, (T)((object)item));
        }

        //
        public List<string> Keys
        {
            get => _collectionDictionary.Keys.ToList();
        }

        // 
        public List<T> Values
        {
            get
            {
                return this._collectionList;
            }
        }

        // 
        private readonly ConcurrentDictionary<string, T> _collectionDictionary;

        // 
        private readonly List<T> _collectionList;

        // 
        [NonSerialized]
        private TC _parent;
    }
}
